fix(cli): serve 按阶段区分「organizations 包缺席」与「插件拒绝挂载」(#4818) - #4858
Merged
xuyushun441-sys merged 1 commit intoAug 3, 2026
Merged
Conversation
…4818) `os serve` ran `importFromHost('@objectstack/organizations')` and `kernel.use(new mod.OrganizationsPlugin())` inside one `try`, so an error the plugin threw while constructing or mounting was reported as "@objectstack/organizations could not be loaded" — an absent package — offered OS_ALLOW_DEGRADED_TENANCY=1 as the way out, and, when that was already set, was downgraded to a warning and the boot continued. Those are two facts with opposite remedies. Split into two stages: - import fails => package ABSENT => unchanged ADR-0093 D5 message and escape hatch; - construct/mount fails => the plugin itself declined => report its error verbatim (message + any `code`, printed generically, never interpreted), say the package WAS found so nobody chases module resolution, state that OS_ALLOW_DEGRADED_TENANCY does not apply, and exit(1) unconditionally. Classification is by which stage threw, never by the error's shape: the package is loaded through `importFromHost`, so CLI and plugin may hold different module instances, and the framework must not encode the plugin's private refusal semantics. D5's posture is unchanged — a deployment that asked for isolation still refuses to boot without it. Only the diagnosis, and the escape hatch's reach, change. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018iARDqtrhQgz6fVHDeDkbQ
|
The latest updates on your projects. Learn more about Vercel for GitHub. 1 Skipped Deployment
|
Contributor
📓 Docs Drift CheckThis PR changes 1 package(s): 20 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:
|
xuyushun441-sys
marked this pull request as ready for review
August 3, 2026 10:26
xuyushun441-sys
enabled auto-merge
August 3, 2026 10:26
xuyushun441-sys
deleted the
claude/issue-4818-split-organizations-import-from-mount
branch
August 3, 2026 10:44
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #4818
问题
packages/cli/src/commands/serve.ts里,importFromHost('@objectstack/organizations')与kernel.use(new mod.OrganizationsPlugin())共用同一个try,于是插件在构造 / 挂载阶段抛出的任何错误都被当成「包加载不出来」上报:文案说@objectstack/organizations could not be loaded,出路里给了OS_ALLOW_DEGRADED_TENANCY=1;而该 env 已设时,更会被降级成一条 warning 并继续启动。这是两件解法相反的事:
OS_ALLOW_DEGRADED_TENANCY代价是实打实的:包明明在镜像里,日志却把人指向模块解析 /
NODE_PATH/ 依赖 prune;更糟的是那条逃生口会吞掉插件自己的拒绝,等于把插件在守的闸门搬到一个 env 变量上(ADR-0049「声明与执行不一致」)。改动
按哪个阶段抛错分类,拆成两段
try:OS_ALLOW_DEGRADED_TENANCY=1逃生口(仍可显式降级启动)。message,以及它自带的code,通用打印、framework 不作解释、不猜原因),明说包已找到并加载、不必去查模块解析,声明OS_ALLOW_DEGRADED_TENANCY对这条路径不适用且设了也过不去,并保留OS_TENANCY_POSTURE=single这个诚实的替代;然后无条件process.exit(1)。判据只看阶段,不看错误形状。 没有引入
err.code === 'MULTI_ORG_NOT_LICENSED'/isMultiOrgLicenseError之类的 cloud 私有谓词:一来 framework 不该编码 cloud 的私有语义(每加一种拒绝理由都要跟着改,是分层违规);二来该包是importFromHost动态加载的,CLI 与它可能持有不同模块实例,instanceof和具名 code 都脆。「谁抛的」是唯一不需要 framework 了解插件内部的切法。ADR-0093 D5 的态度不变:要求了隔离就不能假装有,仍然拒绝启动。变的只是「为什么拒绝」和「告诉 operator 什么」。
测试
新增
packages/cli/test/serve-organizations-mount-failure.e2e.test.ts(放在既有的serve-organizations-host-resolution.e2e.test.ts旁边,复用同一套 spawn 真实 CLI 的 harness —— 这条路径只有真进程能覆盖)。fixture:一个 app 不装该包(import 阶段失败),另一个装一个构造函数就抛错的假包(挂载阶段失败,错误带code)。四个用例:
could not be loaded+ 逃生口仍被提供,不启动;OS_ALLOW_DEGRADED_TENANCY=1⇒ 正常启动并打上 DEGRADED TENANCY 烙印(行为不变,钉住防回归);could not be loaded、退出;OS_ALLOW_DEGRADED_TENANCY=1⇒ 仍然退出(本 issue 的要害:逃生口不再吞掉插件的拒绝)。反向验证(把
serve.tsstash 回改前再跑):3、4 失败,1、2 通过 —— 正好说明新用例是有承重的,且「包缺席」那条路的行为确实分毫未动。已附 changeset(
.changeset/serve-organizations-mount-vs-import.md,@objectstack/clipatch),内含唯一的行为变化说明与迁移建议。未触碰content/docs/releases/。关联
🤖 Generated with Claude Code
https://claude.ai/code/session_018iARDqtrhQgz6fVHDeDkbQ
Generated by Claude Code